package com.openjad.common.util.reflection;

import static com.openjad.common.constant.CharacterConstants.DOT_CHARACTER;

import java.beans.Introspector;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.util.Assert;

import com.openjad.common.constant.FrameworkCode;

//import javassist.CtClass;
//import javassist.CtConstructor;
//import javassist.CtMethod;
//import javassist.NotFoundException;

import com.openjad.common.util.StringUtils;
import com.openjad.logger.api.Logger;
import com.openjad.logger.api.LoggerFactory;

public class ReflectUtils {

	private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);

	private static final String SETTER_PREFIX = "set";

	private static final String GETTER_PREFIX = "get";

	private static final String CGLIB_CLASS_SEPARATOR = "$$";

	private static final String IS = "is";

	/**
	 * void(V).
	 */
	public static final char JVM_VOID = 'V';

	/**
	 * boolean(Z).
	 */
	public static final char JVM_BOOLEAN = 'Z';

	/**
	 * byte(B).
	 */
	public static final char JVM_BYTE = 'B';

	/**
	 * char(C).
	 */
	public static final char JVM_CHAR = 'C';

	/**
	 * double(D).
	 */
	public static final char JVM_DOUBLE = 'D';

	/**
	 * float(F).
	 */
	public static final char JVM_FLOAT = 'F';

	/**
	 * int(I).
	 */
	public static final char JVM_INT = 'I';

	/**
	 * long(J).
	 */
	public static final char JVM_LONG = 'J';

	/**
	 * short(S).
	 */
	public static final char JVM_SHORT = 'S';

	public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];

	public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)";

	public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)";

	public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)";

	public static final String ARRAY_DESC = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))";

	public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")";

	public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);

	public static final String METHOD_DESC_REGEX = "(?:(" + JAVA_IDENT_REGEX + ")?\\((" + DESC_REGEX + "*)\\)(" + DESC_REGEX + ")?)";

	public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);

	public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")");

	public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V");

	public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z");

	private static final ConcurrentMap<String, Class<?>> DESC_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();

	private static final ConcurrentMap<String, Class<?>> NAME_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();

	private static final ConcurrentMap<String, Method> Signature_METHODS_CACHE = new ConcurrentHashMap<String, Method>();

	private static final ConcurrentMap<String, Method> Signature_METHODS_CACHE2 = new ConcurrentHashMap<String, Method>();

	private ReflectUtils() {
	}

	public static boolean isPrimitives(Class<?> cls) {
		if (cls.isArray()) {
			return isPrimitive(cls.getComponentType());
		}
		return isPrimitive(cls);
	}

	public static boolean isPrimitive(Class<?> cls) {
		return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class
				|| Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
	}

	public static Class<?> getBoxedClass(Class<?> c) {
		if (c == int.class)
			c = Integer.class;
		else if (c == boolean.class)
			c = Boolean.class;
		else if (c == long.class)
			c = Long.class;
		else if (c == float.class)
			c = Float.class;
		else if (c == double.class)
			c = Double.class;
		else if (c == char.class)
			c = Character.class;
		else if (c == byte.class)
			c = Byte.class;
		else if (c == short.class)
			c = Short.class;
		return c;
	}

	/**
	 * is compatible.
	 *
	 * @param c class.
	 * @param o instance.
	 * @return compatible or not.
	 */
	public static boolean isCompatible(Class<?> c, Object o) {
		boolean pt = c.isPrimitive();
		if (o == null)
			return !pt;

		if (pt) {
			if (c == int.class)
				c = Integer.class;
			else if (c == boolean.class)
				c = Boolean.class;
			else if (c == long.class)
				c = Long.class;
			else if (c == float.class)
				c = Float.class;
			else if (c == double.class)
				c = Double.class;
			else if (c == char.class)
				c = Character.class;
			else if (c == byte.class)
				c = Byte.class;
			else if (c == short.class)
				c = Short.class;
		}
		if (c == o.getClass())
			return true;
		return c.isInstance(o);
	}

	/**
	 * is compatible.
	 *
	 * @param cs class array.
	 * @param os object array.
	 * @return compatible or not.
	 */
	public static boolean isCompatible(Class<?>[] cs, Object[] os) {
		int len = cs.length;
		if (len != os.length)
			return false;
		if (len == 0)
			return true;
		for (int i = 0; i < len; i++)
			if (!isCompatible(cs[i], os[i]))
				return false;
		return true;
	}

	public static String getCodeBase(Class<?> cls) {
		if (cls == null)
			return null;
		ProtectionDomain domain = cls.getProtectionDomain();
		if (domain == null)
			return null;
		CodeSource source = domain.getCodeSource();
		if (source == null)
			return null;
		URL location = source.getLocation();
		if (location == null)
			return null;
		return location.getFile();
	}

	/**
	 * get name.
	 * java.lang.Object[][].class "java.lang.Object[][]"
	 *
	 * @param c class.
	 * @return name.
	 */
	public static String getName(Class<?> c) {
		if (c.isArray()) {
			StringBuilder sb = new StringBuilder();
			do {
				sb.append("[]");
				c = c.getComponentType();
			} while (c.isArray());

			return c.getName() + sb.toString();
		}
		return c.getName();
	}

//	public static Class<?> getGenericClass(Class<?> cls) {
//		return getGenericClass(cls, 0);
//	}

//	public static Class<?> getGenericClass(Class<?> cls, int i) {
//		try {
//			if (cls.getGenericInterfaces() == null || cls.getGenericInterfaces().length == 0) {
//				return null;
//			}
//			if (cls.getGenericInterfaces()[0] == null || !(cls.getGenericInterfaces()[0] instanceof ParameterizedType)) {
//				return null;
//			}
//			ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
//
//			if (parameterizedType.getActualTypeArguments() == null || parameterizedType.getActualTypeArguments().length < i + 1) {
//				return null;
//			}
//
//			Object genericClass = parameterizedType.getActualTypeArguments()[i];
//			if (genericClass instanceof ParameterizedType) { // handle nested generic type
//				return (Class<?>) ((ParameterizedType) genericClass).getRawType();
//			} else if (genericClass instanceof GenericArrayType) { // handle array generic type
//				return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
//			} else if (((Class) genericClass).isArray()) {
//				// Requires JDK 7 or higher, Foo<int[]> is no longer GenericArrayType
//				return ((Class) genericClass).getComponentType();
//			} else {
//				return (Class<?>) genericClass;
//			}
//		} catch (Throwable e) {
//			throw new IllegalArgumentException(cls.getName()
//					+ " generic type undefined!", e);
//		}
//	}

	/**
	 * get method name.
	 * "void do(int)", "void do()", "int do(java.lang.String,boolean)"
	 *
	 * @param m method.
	 * @return name.
	 */
	public static String getName(final Method m) {
		StringBuilder ret = new StringBuilder();
		ret.append(getName(m.getReturnType())).append(' ');
		ret.append(m.getName()).append('(');
		Class<?>[] parameterTypes = m.getParameterTypes();
		for (int i = 0; i < parameterTypes.length; i++) {
			if (i > 0)
				ret.append(',');
			ret.append(getName(parameterTypes[i]));
		}
		ret.append(')');
		return ret.toString();
	}

	public static String getSignature(String methodName, Class<?>[] parameterTypes) {
		StringBuilder sb = new StringBuilder(methodName);
		sb.append("(");
		if (parameterTypes != null && parameterTypes.length > 0) {
			boolean first = true;
			for (Class<?> type : parameterTypes) {
				if (first) {
					first = false;
				} else {
					sb.append(",");
				}
				sb.append(type.getName());
			}
		}
		sb.append(")");
		return sb.toString();
	}

	/**
	 * get constructor name.
	 * "()", "(java.lang.String,int)"
	 *
	 * @param c constructor.
	 * @return name.
	 */
	public static String getName(final Constructor<?> c) {
		StringBuilder ret = new StringBuilder("(");
		Class<?>[] parameterTypes = c.getParameterTypes();
		for (int i = 0; i < parameterTypes.length; i++) {
			if (i > 0)
				ret.append(',');
			ret.append(getName(parameterTypes[i]));
		}
		ret.append(')');
		return ret.toString();
	}

	/**
	 * get class desc.
	 * boolean[].class "[Z"
	 * Object.class "Ljava/lang/Object;"
	 *
	 * @param c class.
	 * @return desc.
	 */
	public static String getDesc(Class<?> c) {
		StringBuilder ret = new StringBuilder();

		while (c.isArray()) {
			ret.append('[');
			c = c.getComponentType();
		}

		if (c.isPrimitive()) {
			String t = c.getName();
			if ("void".equals(t))
				ret.append(JVM_VOID);
			else if ("boolean".equals(t))
				ret.append(JVM_BOOLEAN);
			else if ("byte".equals(t))
				ret.append(JVM_BYTE);
			else if ("char".equals(t))
				ret.append(JVM_CHAR);
			else if ("double".equals(t))
				ret.append(JVM_DOUBLE);
			else if ("float".equals(t))
				ret.append(JVM_FLOAT);
			else if ("int".equals(t))
				ret.append(JVM_INT);
			else if ("long".equals(t))
				ret.append(JVM_LONG);
			else if ("short".equals(t))
				ret.append(JVM_SHORT);
		} else {
			ret.append('L');
			ret.append(c.getName().replace('.', '/'));
			ret.append(';');
		}
		return ret.toString();
	}

	/**
	 * get class array desc.
	 * [int.class, boolean[].class, Object.class] "I[ZLjava/lang/Object;"
	 *
	 * @param cs class array.
	 * @return desc.
	 */
	public static String getDesc(final Class<?>[] cs) {
		if (cs.length == 0)
			return "";

		StringBuilder sb = new StringBuilder(64);
		for (Class<?> c : cs)
			sb.append(getDesc(c));
		return sb.toString();
	}

	/**
	 * get method desc.
	 * int do(int arg1) "do(I)I"
	 * void do(String arg1,boolean arg2) "do(Ljava/lang/String;Z)V"
	 *
	 * @param m method.
	 * @return desc.
	 */
	public static String getDesc(final Method m) {
		StringBuilder ret = new StringBuilder(m.getName()).append('(');
		Class<?>[] parameterTypes = m.getParameterTypes();
		for (int i = 0; i < parameterTypes.length; i++)
			ret.append(getDesc(parameterTypes[i]));
		ret.append(')').append(getDesc(m.getReturnType()));
		return ret.toString();
	}

	/**
	 * get constructor desc.
	 * "()V", "(Ljava/lang/String;I)V"
	 *
	 * @param c constructor.
	 * @return desc
	 */
	public static String getDesc(final Constructor<?> c) {
		StringBuilder ret = new StringBuilder("(");
		Class<?>[] parameterTypes = c.getParameterTypes();
		for (int i = 0; i < parameterTypes.length; i++)
			ret.append(getDesc(parameterTypes[i]));
		ret.append(')').append('V');
		return ret.toString();
	}

	/**
	 * get method desc.
	 * "(I)I", "()V", "(Ljava/lang/String;Z)V"
	 *
	 * @param m method.
	 * @return desc.
	 */
	public static String getDescWithoutMethodName(Method m) {
		StringBuilder ret = new StringBuilder();
		ret.append('(');
		Class<?>[] parameterTypes = m.getParameterTypes();
		for (int i = 0; i < parameterTypes.length; i++)
			ret.append(getDesc(parameterTypes[i]));
		ret.append(')').append(getDesc(m.getReturnType()));
		return ret.toString();
	}

//	/**
//	 * get class desc.
//	 * Object.class "Ljava/lang/Object;"
//	 * boolean[].class "[Z"
//	 *
//	 * @param c class.
//	 * @return desc.
//	 * @throws NotFoundException e
//	 */
//	public static String getDesc(final CtClass c) throws NotFoundException {
//		StringBuilder ret = new StringBuilder();
//		if (c.isArray()) {
//			ret.append('[');
//			ret.append(getDesc(c.getComponentType()));
//		} else if (c.isPrimitive()) {
//			String t = c.getName();
//			if ("void".equals(t))
//				ret.append(JVM_VOID);
//			else if ("boolean".equals(t))
//				ret.append(JVM_BOOLEAN);
//			else if ("byte".equals(t))
//				ret.append(JVM_BYTE);
//			else if ("char".equals(t))
//				ret.append(JVM_CHAR);
//			else if ("double".equals(t))
//				ret.append(JVM_DOUBLE);
//			else if ("float".equals(t))
//				ret.append(JVM_FLOAT);
//			else if ("int".equals(t))
//				ret.append(JVM_INT);
//			else if ("long".equals(t))
//				ret.append(JVM_LONG);
//			else if ("short".equals(t))
//				ret.append(JVM_SHORT);
//		} else {
//			ret.append('L');
//			ret.append(c.getName().replace('.', '/'));
//			ret.append(';');
//		}
//		return ret.toString();
//	}
//	/**
//	 * get method desc.
//	 * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V"
//	 *
//	 * @param m method.
//	 * @return desc.
//	 * @throws NotFoundException e
//	 */
//	public static String getDesc(final CtMethod m) throws NotFoundException {
//		StringBuilder ret = new StringBuilder(m.getName()).append('(');
//		CtClass[] parameterTypes = m.getParameterTypes();
//		for (int i = 0; i < parameterTypes.length; i++)
//			ret.append(getDesc(parameterTypes[i]));
//		ret.append(')').append(getDesc(m.getReturnType()));
//		return ret.toString();
//	}
//	/**
//	 * get constructor desc.
//	 * "()V", "(Ljava/lang/String;I)V"
//	 *
//	 * @param c constructor.
//	 * @return desc
//	 * @throws NotFoundException e
//	 */
//	public static String getDesc(final CtConstructor c) throws NotFoundException {
//		StringBuilder ret = new StringBuilder("(");
//		CtClass[] parameterTypes = c.getParameterTypes();
//		for (int i = 0; i < parameterTypes.length; i++)
//			ret.append(getDesc(parameterTypes[i]));
//		ret.append(')').append('V');
//		return ret.toString();
//	}
//	/**
//	 * get method desc.
//	 * "(I)I", "()V", "(Ljava/lang/String;Z)V".
//	 *
//	 * @param m method.
//	 * @return desc.
//	 * @throws NotFoundException e
//	 */
//	public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException {
//		StringBuilder ret = new StringBuilder();
//		ret.append('(');
//		CtClass[] parameterTypes = m.getParameterTypes();
//		for (int i = 0; i < parameterTypes.length; i++)
//			ret.append(getDesc(parameterTypes[i]));
//		ret.append(')').append(getDesc(m.getReturnType()));
//		return ret.toString();
//	}

	/**
	 * name to desc.
	 * java.util.Map[][] = "[[Ljava/util/Map;"
	 *
	 * @param name name.
	 * @return desc.
	 */
	public static String name2desc(String name) {
		StringBuilder sb = new StringBuilder();
		int c = 0, index = name.indexOf('[');
		if (index > 0) {
			c = (name.length() - index) / 2;
			name = name.substring(0, index);
		}
		while (c-- > 0)
			sb.append("[");
		if ("void".equals(name))
			sb.append(JVM_VOID);
		else if ("boolean".equals(name))
			sb.append(JVM_BOOLEAN);
		else if ("byte".equals(name))
			sb.append(JVM_BYTE);
		else if ("char".equals(name))
			sb.append(JVM_CHAR);
		else if ("double".equals(name))
			sb.append(JVM_DOUBLE);
		else if ("float".equals(name))
			sb.append(JVM_FLOAT);
		else if ("int".equals(name))
			sb.append(JVM_INT);
		else if ("long".equals(name))
			sb.append(JVM_LONG);
		else if ("short".equals(name))
			sb.append(JVM_SHORT);
		else
			sb.append('L').append(name.replace('.', '/')).append(';');
		return sb.toString();
	}

	/**
	 * desc to name.
	 * "[[I" = "int[][]"
	 *
	 * @param desc desc.
	 * @return name.
	 */
	public static String desc2name(String desc) {
		StringBuilder sb = new StringBuilder();
		int c = desc.lastIndexOf('[') + 1;
		if (desc.length() == c + 1) {
			switch (desc.charAt(c)) {
			case JVM_VOID: {
				sb.append("void");
				break;
			}
			case JVM_BOOLEAN: {
				sb.append("boolean");
				break;
			}
			case JVM_BYTE: {
				sb.append("byte");
				break;
			}
			case JVM_CHAR: {
				sb.append("char");
				break;
			}
			case JVM_DOUBLE: {
				sb.append("double");
				break;
			}
			case JVM_FLOAT: {
				sb.append("float");
				break;
			}
			case JVM_INT: {
				sb.append("int");
				break;
			}
			case JVM_LONG: {
				sb.append("long");
				break;
			}
			case JVM_SHORT: {
				sb.append("short");
				break;
			}
			default:
				throw new RuntimeException();
			}
		} else {
			sb.append(desc.substring(c + 1, desc.length() - 1).replace('/', '.'));
		}
		while (c-- > 0)
			sb.append("[]");
		return sb.toString();
	}

	public static Class<?> forName(String name) {
		try {
			return name2class(name);
		} catch (ClassNotFoundException e) {
			throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
		}
	}

	/**
	 * 
	 * name to class.
	 * "boolean" = boolean.class
	 * "java.util.Map[][]" = java.util.Map[][].class
	 * 
	 * @param name name
	 * @return Class instance.
	 * @throws ClassNotFoundException e
	 */
	public static Class<?> name2class(String name) throws ClassNotFoundException {
		return name2class(ClassHelper.getClassLoader(), name);
	}

	/**
	 * name to class.
	 * "boolean" boolean.class
	 * "java.util.Map[][]" java.util.Map[][].class
	 *
	 * @param cl   ClassLoader instance.
	 * @param name name.
	 * @return Class instance.
	 */
	private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException {
		int c = 0, index = name.indexOf('[');
		if (index > 0) {
			c = (name.length() - index) / 2;
			name = name.substring(0, index);
		}
		if (c > 0) {
			StringBuilder sb = new StringBuilder();
			while (c-- > 0)
				sb.append("[");

			if ("void".equals(name))
				sb.append(JVM_VOID);
			else if ("boolean".equals(name))
				sb.append(JVM_BOOLEAN);
			else if ("byte".equals(name))
				sb.append(JVM_BYTE);
			else if ("char".equals(name))
				sb.append(JVM_CHAR);
			else if ("double".equals(name))
				sb.append(JVM_DOUBLE);
			else if ("float".equals(name))
				sb.append(JVM_FLOAT);
			else if ("int".equals(name))
				sb.append(JVM_INT);
			else if ("long".equals(name))
				sb.append(JVM_LONG);
			else if ("short".equals(name))
				sb.append(JVM_SHORT);
			else
				sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;"
			name = sb.toString();
		} else {
			if ("void".equals(name))
				return void.class;
			else if ("boolean".equals(name))
				return boolean.class;
			else if ("byte".equals(name))
				return byte.class;
			else if ("char".equals(name))
				return char.class;
			else if ("double".equals(name))
				return double.class;
			else if ("float".equals(name))
				return float.class;
			else if ("int".equals(name))
				return int.class;
			else if ("long".equals(name))
				return long.class;
			else if ("short".equals(name))
				return short.class;
		}

		if (cl == null)
			cl = ClassHelper.getClassLoader();
		Class<?> clazz = NAME_CLASS_CACHE.get(name);
		if (clazz == null) {
			clazz = Class.forName(name, true, cl);
			NAME_CLASS_CACHE.put(name, clazz);
		}
		return clazz;
	}

	/**
	 * desc to class.
	 * "[Z" boolean[].class
	 * "[[Ljava/util/Map;" java.util.Map[][].class
	 *
	 * @param desc desc.
	 * @return Class instance.
	 * @throws ClassNotFoundException t
	 */
	public static Class<?> desc2class(String desc) throws ClassNotFoundException {
		return desc2class(ClassHelper.getClassLoader(), desc);
	}

	/**
	 * desc to class.
	 * "[Z" => boolean[].class
	 * "[[Ljava/util/Map;" = java.util.Map[][].class
	 *
	 * @param cl   ClassLoader instance.
	 * @param desc desc.
	 * @return Class instance.
	 * @throws ClassNotFoundException e
	 */
	private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException {
		switch (desc.charAt(0)) {
		case JVM_VOID:
			return void.class;
		case JVM_BOOLEAN:
			return boolean.class;
		case JVM_BYTE:
			return byte.class;
		case JVM_CHAR:
			return char.class;
		case JVM_DOUBLE:
			return double.class;
		case JVM_FLOAT:
			return float.class;
		case JVM_INT:
			return int.class;
		case JVM_LONG:
			return long.class;
		case JVM_SHORT:
			return short.class;
		case 'L':
			desc = desc.substring(1, desc.length() - 1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object"
			break;
		case '[':
			desc = desc.replace('/', '.'); // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
			break;
		default:
			throw new ClassNotFoundException("Class not found: " + desc);
		}

		if (cl == null)
			cl = ClassHelper.getClassLoader();
		Class<?> clazz = DESC_CLASS_CACHE.get(desc);
		if (clazz == null) {
			clazz = Class.forName(desc, true, cl);
			DESC_CLASS_CACHE.put(desc, clazz);
		}
		return clazz;
	}

	/**
	 * get class array instance.
	 *
	 * @param desc desc.
	 * @return Class class array.
	 * @throws ClassNotFoundException e
	 */
	public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException {
		Class<?>[] ret = desc2classArray(ClassHelper.getClassLoader(), desc);
		return ret;
	}

	/**
	 * get class array instance.
	 *
	 * @param cl   ClassLoader instance.
	 * @param desc desc.
	 * @return Class[] class array.
	 * @throws ClassNotFoundException e
	 */
	private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException {
		if (desc.length() == 0)
			return EMPTY_CLASS_ARRAY;

		List<Class<?>> cs = new ArrayList<Class<?>>();
		Matcher m = DESC_PATTERN.matcher(desc);
		while (m.find())
			cs.add(desc2class(cl, m.group()));
		return cs.toArray(EMPTY_CLASS_ARRAY);
	}

	/**
	 * Find method from method signature
	 *
	 * @param clazz          Target class to find method
	 * @param methodName     Method signature, e.g.: method1(int, String). It is allowed to provide method name only, e.g.: method2
	 * @param parameterTypes parameterTypes
	 * @return target method
	 * @throws NoSuchMethodException  e
	 * @throws ClassNotFoundException e
	 * @throws IllegalStateException  when multiple methods are found (overridden method when parameter info is not provided)
	 */
	public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes)
			throws NoSuchMethodException, ClassNotFoundException {
		String signature = clazz.getName() + "." + methodName;
		if (parameterTypes != null && parameterTypes.length > 0) {
			signature += StringUtils.join(parameterTypes);
		}
		Method method = Signature_METHODS_CACHE.get(signature);
		if (method != null) {
			return method;
		}
		if (parameterTypes == null) {
			List<Method> finded = new ArrayList<Method>();
			for (Method m : clazz.getMethods()) {
				if (m.getName().equals(methodName)) {
					finded.add(m);
				}
			}
			if (finded.isEmpty()) {
				throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
			}
			if (finded.size() > 1) {
				String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
						methodName, clazz.getName(), finded.size());
				throw new IllegalStateException(msg);
			}
			method = finded.get(0);
		} else {
			Class<?>[] types = new Class<?>[parameterTypes.length];
			for (int i = 0; i < parameterTypes.length; i++) {
				types[i] = name2class(parameterTypes[i]);
			}
			method = clazz.getMethod(methodName, types);

		}
		Signature_METHODS_CACHE.put(signature, method);
		return method;
	}

	public static Method findMethodByMethodSignatureAndTypes(Class<?> clazz, String methodName, Class[] parameterTypes)
			throws NoSuchMethodException, ClassNotFoundException {

		String signature = clazz.getName() + "." + methodName;
		if (parameterTypes != null && parameterTypes.length > 0) {
//            signature += StringUtils.join(parameterTypes);
			for (Class parameterType : parameterTypes) {
				signature += parameterType.getName();
			}
		}
		Method method = Signature_METHODS_CACHE2.get(signature);
		if (method != null) {
			return method;
		}
		if (parameterTypes == null) {
			List<Method> finded = new ArrayList<Method>();
			for (Method m : clazz.getMethods()) {
				if (m.getName().equals(methodName)) {
					finded.add(m);
				}
			}
			if (finded.isEmpty()) {
				throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
			}
			if (finded.size() > 1) {
				String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
						methodName, clazz.getName(), finded.size());
				throw new IllegalStateException(msg);
			}
			method = finded.get(0);
		} else {
			Class<?>[] types = parameterTypes;
//            Class<?>[] types = new Class<?>[parameterTypes.length];
//            for (int i = 0; i < parameterTypes.length; i++) {
//                types[i] = name2class(parameterTypes[i]);
//            }
			method = clazz.getMethod(methodName, types);

		}
		Signature_METHODS_CACHE2.put(signature, method);
		return method;

	}

	public static Method findMethodByMethodName(Class<?> clazz, String methodName)
			throws NoSuchMethodException, ClassNotFoundException {
		return findMethodByMethodSignature(clazz, methodName, null);
	}

	public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException {
		Constructor<?> targetConstructor;
		try {
			targetConstructor = clazz.getConstructor(new Class<?>[] { paramType });
		} catch (NoSuchMethodException e) {
			targetConstructor = null;
			Constructor<?>[] constructors = clazz.getConstructors();
			for (Constructor<?> constructor : constructors) {
				if (Modifier.isPublic(constructor.getModifiers())
						&& constructor.getParameterTypes().length == 1
						&& constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {
					targetConstructor = constructor;
					break;
				}
			}
			if (targetConstructor == null) {
				throw e;
			}
		}
		return targetConstructor;
	}

	/**
	 * Check if one object is the implementation for a given interface.
	 * <p>
	 * This method will not trigger classloading for the given interface, therefore it will not lead to error when
	 * the given interface is not visible by the classloader
	 *
	 * @param obj                Object to examine
	 * @param interfaceClazzName The given interface
	 * @return true if the object implements the given interface, otherwise return false
	 */
	public static boolean isInstance(Object obj, String interfaceClazzName) {
		for (Class<?> clazz = obj.getClass();
				clazz != null && !clazz.equals(Object.class);
				clazz = clazz.getSuperclass()) {
			Class<?>[] interfaces = clazz.getInterfaces();
			for (Class<?> itf : interfaces) {
				if (itf.getName().equals(interfaceClazzName)) {
					return true;
				}
			}
		}
		return false;
	}

	public static Object getEmptyObject(Class<?> returnType) {
		return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0);
	}

	private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) {
		if (level > 2)
			return null;
		if (returnType == null) {
			return null;
		} else if (returnType == boolean.class || returnType == Boolean.class) {
			return false;
		} else if (returnType == char.class || returnType == Character.class) {
			return '\0';
		} else if (returnType == byte.class || returnType == Byte.class) {
			return (byte) 0;
		} else if (returnType == short.class || returnType == Short.class) {
			return (short) 0;
		} else if (returnType == int.class || returnType == Integer.class) {
			return 0;
		} else if (returnType == long.class || returnType == Long.class) {
			return 0L;
		} else if (returnType == float.class || returnType == Float.class) {
			return 0F;
		} else if (returnType == double.class || returnType == Double.class) {
			return 0D;
		} else if (returnType.isArray()) {
			return Array.newInstance(returnType.getComponentType(), 0);
		} else if (returnType.isAssignableFrom(ArrayList.class)) {
			return new ArrayList<Object>(0);
		} else if (returnType.isAssignableFrom(HashSet.class)) {
			return new HashSet<Object>(0);
		} else if (returnType.isAssignableFrom(HashMap.class)) {
			return new HashMap<Object, Object>(0);
		} else if (String.class.equals(returnType)) {
			return "";
		} else if (!returnType.isInterface()) {
			try {
				Object value = emptyInstances.get(returnType);
				if (value == null) {
					value = returnType.newInstance();
					emptyInstances.put(returnType, value);
				}
				Class<?> cls = value.getClass();
				while (cls != null && cls != Object.class) {
					Field[] fields = cls.getDeclaredFields();
					for (Field field : fields) {
						if (field.isSynthetic()) {
							continue;
						}
						Object property = getEmptyObject(field.getType(), emptyInstances, level + 1);
						if (property != null) {
							try {
								if (!field.isAccessible()) {
									field.setAccessible(true);
								}
								field.set(value, property);
							} catch (Throwable e) {
							}
						}
					}
					cls = cls.getSuperclass();
				}
				return value;
			} catch (Throwable e) {
				return null;
			}
		} else {
			return null;
		}
	}

	public static boolean isBeanPropertyReadMethod(Method method) {
		return method != null
				&& Modifier.isPublic(method.getModifiers())
				&& !Modifier.isStatic(method.getModifiers())
				&& method.getReturnType() != void.class
				&& method.getDeclaringClass() != Object.class
				&& method.getParameterTypes().length == 0
				&& ((method.getName().startsWith("get") && method.getName().length() > 3)
						|| (method.getName().startsWith("is") && method.getName().length() > 2));
	}

	public static String getPropertyNameFromBeanReadMethod(Method method) {
		if (isBeanPropertyReadMethod(method)) {
			if (method.getName().startsWith("get")) {
				return method.getName().substring(3, 4).toLowerCase()
						+ method.getName().substring(4);
			}
			if (method.getName().startsWith("is")) {
				return method.getName().substring(2, 3).toLowerCase()
						+ method.getName().substring(3);
			}
		}
		return null;
	}

	public static boolean isBeanPropertyWriteMethod(Method method) {
		return method != null
				&& Modifier.isPublic(method.getModifiers())
				&& !Modifier.isStatic(method.getModifiers())
				&& method.getDeclaringClass() != Object.class
				&& method.getParameterTypes().length == 1
				&& method.getName().startsWith("set")
				&& method.getName().length() > 3;
	}

	public static String getPropertyNameFromBeanWriteMethod(Method method) {
		if (isBeanPropertyWriteMethod(method)) {
			return method.getName().substring(3, 4).toLowerCase()
					+ method.getName().substring(4);
		}
		return null;
	}

	public static boolean isPublicInstanceField(Field field) {
		return Modifier.isPublic(field.getModifiers())
				&& !Modifier.isStatic(field.getModifiers())
				&& !Modifier.isFinal(field.getModifiers())
				&& !field.isSynthetic();
	}

	public static Map<String, Field> getBeanPropertyFields(Class cl) {
		Map<String, Field> properties = new HashMap<String, Field>();
		for (; cl != null; cl = cl.getSuperclass()) {
			Field[] fields = cl.getDeclaredFields();
			for (Field field : fields) {
				if (Modifier.isTransient(field.getModifiers())
						|| Modifier.isStatic(field.getModifiers())) {
					continue;
				}

				field.setAccessible(true);

				properties.put(field.getName(), field);
			}
		}

		return properties;
	}

	public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {
		Map<String, Method> properties = new HashMap<String, Method>();
		for (; cl != null; cl = cl.getSuperclass()) {
			Method[] methods = cl.getDeclaredMethods();
			for (Method method : methods) {
				if (isBeanPropertyReadMethod(method)) {
					method.setAccessible(true);
					String property = getPropertyNameFromBeanReadMethod(method);
					properties.put(property, method);
				}
			}
		}

		return properties;
	}

	/**
	 * 
	 * @param obj
	 *                     p
	 * @param propertyName
	 *                     p
	 * @return p
	 */
	public static Object invokeGetter(Object obj, String propertyName) {
		Object object = obj;
		for (String name : StringUtils.split(propertyName, DOT_CHARACTER)) {
			String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
			object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
		}
		return object;
	}

	/**
	 * 
	 * @param obj
	 *                     p
	 * @param propertyName
	 *                     p
	 * @param value
	 *                     p
	 */
	public static void invokeSetter(Object obj, String propertyName, Object value) {
		Object object = obj;
		String[] names = StringUtils.split(propertyName, DOT_CHARACTER);
		for (int i = 0; i < names.length; i++) {
			if (i < names.length - 1) {
				String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
				object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
			} else {
				String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
				invokeMethodByName(object, setterMethodName, new Object[] { value });
			}
		}
	}

	/**
	 * 
	 * @param obj
	 *                  p
	 * @param fieldName
	 *                  p
	 * @return p
	 */
	public static Object getFieldValue(final Object obj, final String fieldName) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new ReflectionException(FrameworkCode.CODE_00011, "在目标对象[" + obj + "]中找不到属性 [" + fieldName + "] ");
		}

		Object result = null;
		try {
			result = field.get(obj);
		} catch (IllegalAccessException e) {
			logger.error(FrameworkCode.CODE_00010, "不可能抛出的异常," + e.getMessage(), e);
		}
		return result;
	}

	/**
	 * 
	 * @param obj
	 *                  p
	 * @param fieldName
	 *                  p
	 * @param value
	 *                  p
	 */
	public static void setFieldValue(final Object obj, final String fieldName, final Object value) {

		Assert.notNull(obj, "object 不能为空");
		Assert.notNull(fieldName, "fieldName 不能为空");

		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new ReflectionException(FrameworkCode.CODE_00011,
					"找不到属性 [" + fieldName + "] 目标类型:[" + obj.getClass().getName() + "]");
		}

		if (value != null) {
			if (!field.getType().isAssignableFrom(value.getClass())) {
				throw new ReflectionException(FrameworkCode.CODE_00013,
						"类型不兼容，不能尝试把一个类型为[" + value.getClass().getName()
								+ "]的值赋给类型为[" + field.getType() + "]的属性,object:" + obj.getClass().getName());
			}
		}
		try {
			field.set(obj, value);
		} catch (IllegalAccessException e) {
			logger.error(FrameworkCode.CODE_00010, "不可能抛出的异常," + e.getMessage(), e);
		}
	}

	/**
	 * 
	 * @param obj
	 *                       p
	 * @param methodName
	 *                       p
	 * @param parameterTypes
	 *                       p
	 * @param args
	 *                       p
	 * @return p
	 */
	public static Object invokeMethod(final Object obj, final String methodName,
			final Class<?>[] parameterTypes, final Object[] args) {

		Method method = getAccessibleMethod(obj, methodName, parameterTypes);
		if (method == null) {
			throw new ReflectionException(FrameworkCode.CODE_00012, "在目标对象[" + obj + "]中找不到方法 [" + methodName + "]");
		}
		try {
			return method.invoke(obj, args);
		} catch (Exception e) {
			throw new ReflectionException(FrameworkCode.CODE_00010, e);
		}
	}

	/**
	 * 
	 * @param obj
	 *                   p
	 * @param methodName
	 *                   p
	 * @param args
	 *                   p
	 * @return p
	 */
	public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
		Method method = getAccessibleMethodByName(obj, methodName);
		if (method == null) {
			throw new ReflectionException(FrameworkCode.CODE_00012, "在目标对象[" + obj + "]中找不到方法 [" + methodName + "]");
		}
		try {
			return method.invoke(obj, args);
		} catch (Exception e) {
			throw new ReflectionException(FrameworkCode.CODE_00010, e);
		}
	}

	/**
	 * 
	 * @param obj
	 *                  p
	 * @param fieldName
	 *                  p
	 * @return p
	 */
	public static Field getAccessibleField(final Object obj, final String fieldName) {
		Assert.notNull(obj, "object 不能为空");
		Assert.notNull(fieldName, "fieldName 不能为空");
		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
			try {
				Field field = superClass.getDeclaredField(fieldName);
				makeAccessible(field);
				return field;
			} catch (NoSuchFieldException e) {
				continue;
			}
		}
		return null;
	}

	/**
	 * 
	 * @param clazz
	 *              p
	 * @return p
	 */
	public static Set<Field> getClassFields(Class<?> clazz) {
		Set<Field> result = new LinkedHashSet<Field>();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (Modifier.isStatic(field.getModifiers())) {
				continue;
			}
			if (Modifier.isTransient(field.getModifiers())) {
				continue;
			}
			result.add(field);
		}

		Class<?> superClass = clazz.getSuperclass();
		if (superClass.equals(Object.class)) {
			return result;
		}
		result.addAll(getClassFields(superClass));
		return result;
	}

	public static <T extends Annotation> boolean hasAnnotation(Method method, Class<T> annotationClass) {
		return (method.getAnnotation(annotationClass)) != null ? true : false;
	}

	public static <T extends Annotation> boolean hasAnnotation(Field field, Class<T> annotationClass) {
		return (field.getAnnotation(annotationClass)) != null ? true : false;
	}

	//	

	/**
	 * 
	 * @param obj
	 *                       p
	 * @param methodName
	 *                       p
	 * @param parameterTypes
	 *                       p
	 * @return p
	 */
	public static Method getAccessibleMethod(final Object obj, final String methodName,
			final Class<?>... parameterTypes) {

		Assert.notNull(obj, "object 不能为空");
		Assert.notNull(methodName, "methodName 不能为空");

		for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
			try {
				Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
				makeAccessible(method);
				return method;
			} catch (NoSuchMethodException e) {
				// Method不在当前类定义,继续向上转型
				continue;
			}
		}
		return null;
	}

	/**
	 * 
	 * @param obj
	 *                   p
	 * @param methodName
	 *                   p
	 * @return p
	 */
	public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
		Assert.notNull(obj, "object 不能为空");
		Assert.notNull(methodName, "methodName 不能为空");

		for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
			Method[] methods = searchType.getDeclaredMethods();
			for (Method method : methods) {
				if (method.getName().equals(methodName)) {
					makeAccessible(method);
					return method;
				}
			}
		}
		return null;
	}

	/**
	 * 
	 * @param method
	 *               p
	 */
	public static void makeAccessible(Method method) {
		boolean isNotPub = !Modifier.isPublic(method.getModifiers())
				|| !Modifier.isPublic(method.getDeclaringClass().getModifiers());
		if (isNotPub && !method.isAccessible()) {
			method.setAccessible(true);
		}
	}

	public static <T> Class<T> getSuperClassGenricType(final Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	public static Class getSuperClassGenricType(final Class clazz, final int index) {
		Type genType = clazz.getGenericSuperclass();
		return getGenricType(genType, clazz, index);
	}

	/**
	 * 
	 * @param clazz
	 *              p
	 * @param index
	 *              p
	 * @return p
	 */
	public static Class getSuperInterfaceGenricType(final Class clazz, final int index) {
		Type[] genTypes = clazz.getGenericInterfaces();
		if (genTypes == null || genTypes.length == 0) {
			logger.warn(clazz.getName() + " 没有实现接口 ");
			return Object.class;
		}
		return getGenricType(genTypes[0], clazz, index);
	}

	/**
	 * 
	 * @param clazz
	 *              p
	 * @return p
	 */
	public static Class getSuperInterfaceGenricType(final Class clazz) {
		return getSuperInterfaceGenricType(clazz, 0);
	}

	/**
	 * 
	 * @param genType
	 *                p
	 * @param clazz
	 *                p
	 * @param index
	 *                p
	 * @return p
	 */
	private static Class getGenricType(Type genType, final Class clazz, final int index) {
		if (!(genType instanceof ParameterizedType)) {
			logger.warn(clazz.getName() + " 的父类不是参数化类型 ");
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			logger.warn("Index: " + index + ", Size of " + clazz.getName()
					+ "'s Parameterized Type: " + params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			logger.warn(clazz.getName() + " 未对超类泛型参数设置实际类 ");
			return Object.class;
		}
		return (Class) params[index];
	}

	/**
	 * 
	 * @param instance
	 *                 p
	 * @return p
	 */
	public static Class<?> getUsperClass(Object instance) {
		if (instance == null) {
			throw new IllegalArgumentException("Instance 不能为空");
		}
		Class clazz = instance.getClass();
		if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
			Class<?> superClass = clazz.getSuperclass();
			if (superClass != null && !Object.class.equals(superClass)) {
				return superClass;
			}
		}
		return clazz;

	}

	/**
	 * 查找对你的getter方法
	 * 
	 * @param containerClass
	 *                       p
	 * @param propertyName
	 *                       p
	 * @return p
	 */
	public static Method findGetterMethod(Class containerClass, String propertyName) {
		Class checkClass = containerClass;
		Method getter = null;

		while (getter == null && checkClass != null) {
			if (checkClass.equals(Object.class)) {
				break;
			}
			getter = getGetterOrNull(checkClass, propertyName);
			checkClass = checkClass.getSuperclass();
		}

		if (getter == null) {
			for (Class theInterface : containerClass.getInterfaces()) {
				getter = getGetterOrNull(theInterface, propertyName);
				if (getter != null) {
					break;
				}
			}
		}

		if (getter == null) {
			String err = String.format(Locale.ROOT, "没有找到属性  [%s#%s] 对应的get方法",
					containerClass.getName(), propertyName);
			throw new ReflectionException(FrameworkCode.CODE_00014, err);
		}

		getter.setAccessible(true);
		return getter;
	}

	/**
	 * 获得对像的setter方法
	 * 
	 * @param containerClass
	 *                       p
	 * @param propertyName
	 *                       p
	 * @param propertyType
	 *                       p
	 * @return p
	 */
	public static Method findSetterMethod(Class containerClass, String propertyName, Class propertyType) {
		Class checkClass = containerClass;
		Method setter = null;

		while (setter == null && checkClass != null) {
			if (checkClass.equals(Object.class)) {
				break;
			}

			setter = setterOrNull(checkClass, propertyName, propertyType);
			checkClass = checkClass.getSuperclass();
		}

		if (setter == null) {
			for (Class theInterface : containerClass.getInterfaces()) {
				setter = setterOrNull(theInterface, propertyName, propertyType);
				if (setter != null) {
					break;
				}
			}
		}

		if (setter == null) {
			String err = String.format(Locale.ROOT, "没有找到属性 [%s#%s]对应的set方法",
					containerClass.getName(), propertyName);
			throw new ReflectionException(FrameworkCode.CODE_00014, err);
		}

		setter.setAccessible(true);
		return setter;
	}

	/**
	 * 
	 * @param containerClass
	 *                       p
	 * @param propertyName
	 *                       p
	 * @return p
	 */
	private static Method getGetterOrNull(Class containerClass, String propertyName) {
		for (Method method : containerClass.getDeclaredMethods()) {
			if (method.getParameterTypes().length != 0) {
				continue;
			}
			if (method.isBridge()) {
				continue;
			}

			final String methodName = method.getName();

			if (methodName.startsWith(GETTER_PREFIX)) {
				final String stemName = methodName.substring(3);
				final String decapitalizedStemName = Introspector.decapitalize(stemName);
				if (stemName.equals(propertyName) || decapitalizedStemName.equals(propertyName)) {
					verifyNoIsVariantExists(containerClass, propertyName, method, stemName);
					return method;
				}

			}

			if (methodName.startsWith(IS)) {
				final String stemName = methodName.substring(2);
				String decapitalizedStemName = Introspector.decapitalize(stemName);
				if (stemName.equals(propertyName) || decapitalizedStemName.equals(propertyName)) {
					verifyNoGetVariantExists(containerClass, propertyName, method, stemName);
					return method;
				}
			}
		}

		return null;
	}

	/**
	 * 
	 * @param containerClass
	 *                       p
	 * @param propertyName
	 *                       p
	 * @param isMethod
	 *                       p
	 * @param stemName
	 *                       p
	 */
	@SuppressWarnings("unchecked")
	private static void verifyNoGetVariantExists(Class containerClass, String propertyName,
			Method isMethod, String stemName) {
		try {
			final Method getMethod = containerClass.getDeclaredMethod(GETTER_PREFIX + stemName);
			checkGetAndIsVariants(containerClass, propertyName, getMethod, isMethod);
		} catch (NoSuchMethodException ignore) {
		}
	}

	/**
	 * 
	 * @param containerClass
	 *                       p
	 * @param propertyName
	 *                       p
	 * @param getMethod
	 *                       p
	 * @param stemName
	 *                       p
	 */
	@SuppressWarnings("unchecked")
	private static void verifyNoIsVariantExists(Class containerClass, String propertyName,
			Method getMethod, String stemName) {
		try {
			final Method isMethod = containerClass.getDeclaredMethod(IS + stemName);
			checkGetAndIsVariants(containerClass, propertyName, getMethod, isMethod);
		} catch (NoSuchMethodException ignore) {
		}
	}

	/**
	 * 
	 * @param containerClass
	 *                       p
	 * @param propertyName
	 *                       p
	 * @param getMethod
	 *                       p
	 * @param isMethod
	 *                       p
	 */
	private static void checkGetAndIsVariants(
			Class containerClass, String propertyName,
			Method getMethod, Method isMethod) {
		if (!isMethod.getReturnType().equals(getMethod.getReturnType())) {
			String err = "尝试获取类[%s]的属性[%s]的get方法时，没有找到对应的get[%s]或is[%s]方法";
			err = String.format(Locale.ROOT, err, containerClass.getName(), propertyName,
					getMethod.toString(), isMethod.toString());
			throw new ReflectionException(FrameworkCode.CODE_00014, err);
		}
	}

	/**
	 * 
	 * @param theClass
	 *                     p
	 * @param propertyName
	 *                     p
	 * @param propertyType
	 *                     p
	 * @return p
	 */
	private static Method setterOrNull(Class theClass, String propertyName, Class propertyType) {
		Method potentialSetter = null;
		for (Method method : theClass.getDeclaredMethods()) {
			final String methodName = method.getName();
			if (method.getParameterTypes().length == 1 && methodName.startsWith(SETTER_PREFIX)) {
				final String testOldMethod = methodName.substring(3);
				final String testStdMethod = Introspector.decapitalize(testOldMethod);
				if (testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName)) {
					potentialSetter = method;
					if (propertyType == null || method.getParameterTypes()[0].equals(propertyType)) {
						break;
					}
				}
			}
		}
		return potentialSetter;
	}

	public static void getField(List<Field> fields, Class<?> clazz) {
		if (clazz.getSuperclass() != null) {
			getField(fields, clazz.getSuperclass());
		}

		Class[] interfaces = clazz.getInterfaces();
		for (Class inf : interfaces) {
			getField(fields, inf);
		}

		Field[] fields0 = clazz.getDeclaredFields();
		for (Field field : fields0) {
			makeAccessible(field);
		}
		Collections.addAll(fields, fields0);
	}

	/**
	 * 
	 * @param field
	 *              p
	 */
	public static void makeAccessible(Field field) {
		if (!field.isAccessible() && (!Modifier.isPublic(field.getModifiers())
				|| !Modifier.isPublic(field.getDeclaringClass().getModifiers())
				|| Modifier.isFinal(field.getModifiers()))) {
			field.setAccessible(true);
		}
	}

	public static <T> T createInstance(Class<T> clazz, Object... params) {
		try {
			Constructor[] constructors = clazz.getConstructors();
			if (constructors.length == 0) {
				throw new ReflectionException(FrameworkCode.CODE_00012, "没有找到构造方法," + clazz.getName());
			}

			if (params == null || params.length == 0) {
				for (Constructor ct : constructors) {
					if (ct.getParameterTypes().length == 0) {
						return (T) ct.newInstance();
					}

				}
			} else {
				boolean found;
				Class<?>[] paramClass = new Class[params.length];
				for (int idx = 0; idx < params.length; idx++) {
					if (params[idx] == null) {
						paramClass[idx] = null;
					} else {
						paramClass[idx] = params[idx].getClass();
					}
				}
				for (Constructor ct : constructors) {
					Class<?>[] cls = ct.getParameterTypes();
					if (cls.length != params.length) {
						continue;
					}
					found = true;
					for (int idx = 0; idx < cls.length; idx++) {
						if (paramClass[idx] == null) {
							continue;
						}
						Class tmp = cls[idx];
						if (!tmp.isAssignableFrom(paramClass[idx])) {
							found = false;
							break;
						}
					}
					if (found) {
						return (T) ct.newInstance(params);
					}
				}
			}
			throw new ReflectionException(FrameworkCode.CODE_00012, "没有找到构造方法");
		} catch (Throwable t) {
			throw new ReflectionException(FrameworkCode.CODE_00010, "通过返射实例化对象失败," + t.getMessage(), t);
		}

	}
}
